/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  SpiSlave_Mld.h
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL SpiSlave_Slave plugins.
 */

#ifndef MLD_SPI_SLV_H_
#define MLD_SPI_SLV_H_

#ifdef __cplusplus
extern "C" {
#endif

#include "Compiler.h"

#if defined(SPI_SLV_DEBUG_LOG)
#include "debug.h"
#define SPI_SLV_DBG  PRINT
#else
#define SPI_SLV_DBG(...)
#endif

enum spi_slv_tim_mode {
    MODE0 = 0U,
    MODE1,
    MODE2,
    MODE3
};


enum spi_slv_state {
    SPI_SLV_STATE_UNINIT = 0x0U,
    SPI_SLV_STATE_INITED = 0x1U,
    SPI_SLV_STATE_BUSY_TX = 0x02U,
    SPI_SLV_STATE_BUSY_RX = 0x04U,
    SPI_SLV_STATE_IRQ_ACT = 0x08U,
    SPI_SLV_STATE_DMA_TX = 0x10U,
    SPI_SLV_STATE_DMA_RX = 0x20U,
    SPI_SLV_STATE_IRQ_TX = 0x40U,
    SPI_SLV_STATE_IRQ_RX = 0x80U,
    SPI_SLV_STATE_IS_UNS_EN = 0x200U,
    SPI_SLV_STATE_ERR_END = 0x400U,
    SPI_SLV_STATE_CS_INVLD_EN = 0x1000U,
    SPI_SLV_STATE_EN_VLD_CS = 0x2000U,
};

enum ret_err {
    SLV_ERR_NONE = 0U,
    SLV_ERR_NO_INIT,
    SLV_ERR_API_OPS,
    SLV_ERR_NO_BUS,
    SLV_ERR_LOW_LEVEL,
    SLV_ERR_BUSY,
};

enum spi_slv_dir {
    SPI_SLV_DIR_RX = 0U,
    SPI_SLV_DIR_TX = 1U,
};

enum spi_slv_ops_type {
    MODE_NORMAL = 0U,
    MODE_IRQ = 1U,
    MODE_DMA = 2U,
};

enum fifo_state {
    SPI_SLV_RX_FIFO_READ =  0x01U,
    SPI_SLV_TX_FIFO_WRITE = 0x02U,
    SPI_SLV_TX_FIFO_UDR = 0x04U,
    SPI_SLV_RX_FIFO_OVR = 0x08U,
    SPI_SLV_TX_DMA_ERR = 0x10U,
    SPI_SLV_RX_DMA_ERR = 0x20U,
    SPI_SLV_PARITY_ERR = 0x40U,
};

enum fifo_width {
    SPI_SLV_DATA_WIDTH_BYTE = 0U,
    SPI_SLV_DATA_WIDTH_HALF_WORD,
    SPI_SLV_DATA_WIDTH_WORD
};

#define    SPI_SLV_TRASPORT_FINISH  0x01U
#define    SPI_SLV_RX_READ_REQ  0x02U
#define    SPI_SLV_TX_WRITE_REQ  0x04U
#define    SPI_SLV_CS_INVLD_REQ  0x08U

#define SPI_SLV_BUS_BUSY_MASK   (SPI_SLV_STATE_BUSY_TX|SPI_SLV_STATE_BUSY_RX)
#define SPI_SLV_BUS_BUSY_DMA_MASK   (SPI_SLV_STATE_DMA_TX|SPI_SLV_STATE_DMA_RX)
#define SPI_SLV_BUS_BUSY_IRQ_MASK   (SPI_SLV_STATE_IRQ_TX|SPI_SLV_STATE_IRQ_RX)
#define SPI_SLV_BUS_FIFO_STATE_ERR_MASK (SPI_SLV_TX_FIFO_UDR|SPI_SLV_RX_FIFO_OVR|\
                                        SPI_SLV_TX_DMA_ERR|SPI_SLV_RX_DMA_ERR|SPI_SLV_PARITY_ERR)
#define SPI_SLV_BUS_BUSY_ASYNC_MASK    (SPI_SLV_BUS_BUSY_DMA_MASK|SPI_SLV_BUS_BUSY_IRQ_MASK)
#define SPI_SLV_BUS_BUSY_STATUS_MASK    (SPI_SLV_BUS_BUSY_MASK|SPI_SLV_BUS_BUSY_ASYNC_MASK)
#define SPI_SLV_BUS_BUSY_SYNC_MASK    (SPI_SLV_BUS_BUSY_MASK)


#define SPI_SLV_STATE_EXT_FLAGS     (SPI_SLV_STATE_IS_UNS_EN | \
                                        SPI_SLV_STATE_CS_INVLD_EN | SPI_SLV_STATE_EN_VLD_CS)

struct mld_spi_slv_module;
struct mld_spi_slv_device;
struct mld_spi_slv_async;

struct mld_spi_slv_ops {
    sint32 (*spi_slv_init)(struct mld_spi_slv_module *bus);
    sint32 (*spi_slv_deinit)(struct mld_spi_slv_module *bus);
    void (*spi_slv_write_data)(struct mld_spi_slv_module  *bus, uint32 data);
    uint32 (*spi_slv_read_data)(struct mld_spi_slv_module  *bus);
    boolean (*spi_slv_can_write)(struct mld_spi_slv_module  *bus);
    boolean (*spi_slv_can_read)(struct mld_spi_slv_module  *bus);
    void (*spi_slv_setup_irq_mask)(struct mld_spi_slv_module  *bus, \
                               uint32 type);
    void (*spi_slv_clr_irq_state)(struct mld_spi_slv_module  *bus, uint32 clr);

    sint32 (*spi_slv_set_predev_config)(struct mld_spi_slv_module *bus, \
                                    struct mld_spi_slv_device *dev);
    sint32 (*spi_slv_vector_transmit_receive)(struct mld_spi_slv_module  *bus, \
                                          struct mld_spi_slv_device *dev, \
                                          struct mld_spi_slv_async *vector, \
                                          uint32 timeout);
    sint32 (*spi_slv_vector_transmit_receive_irq)(struct mld_spi_slv_module  *bus, \
            struct mld_spi_slv_device *dev, \
            struct mld_spi_slv_async *vector);
    sint32 (*spi_slv_vector_transmit_receive_dma)(struct mld_spi_slv_module  *bus, \
            struct mld_spi_slv_device *dev, \
            struct mld_spi_slv_async *vector);
    uint32 (*spi_slv_irq_state)(struct mld_spi_slv_module *bus, uint32 *irq_status);
    void (*spi_slv_dma_stop)(struct mld_spi_slv_module *bus);
    void (*spi_slv_transmit_stop)(struct mld_spi_slv_module *bus);
    uint16 (*spi_slv_transmit_length)(const struct mld_spi_slv_module *bus);
};

union spi_slv_data_ptr {
    /* data */
    uint32  val;
    uint8  *u8_ptr;
    uint16 *u16_ptr;
    uint32 *u32_ptr;
};

struct mld_spi_slv_async {
    /* async mode need this*/
    uint32 len;
    /* prxdata */
    union spi_slv_data_ptr prxdata;
    /* ptxdata */
    union spi_slv_data_ptr ptxdata;
    /* data_width */
    enum fifo_width width_type;
    /* prxdata */
    uint32 rx_cur;
    /* ptxdata */
    uint32 tx_cur;
    /* remain of this item */
    uint32 cur_remian;
    /* once except of this item */
    uint32 expect_len;
    /* is dummy tx  */
    uint8 istxDummy;
    /* is dummy rx  */
    uint8 isrxDummy;
};

struct mld_spi_slv_module {
    volatile uint32 base;
    /* bus num */
    uint8        idx;
    /* status */
    uint32      state;
    /* spi common ops*/
    const struct mld_spi_slv_ops *bus_ops;
    /* ip special ops and params */
    void *priv;
    /* slave mode params  or soft cs pin id*/
    void *dev_mode;
    /* asycn mode need this*/
    struct mld_spi_slv_async async;
};

struct mld_spi_slv_device {
    /* spi bus ops*/
    struct mld_spi_slv_module *bus;
    /* device special ops and params */
    void *priv;
};
/*PRQA S 0779,0777 30*/
sint32 mld_spi_slv_init(struct mld_spi_slv_module *bus);

sint32 mld_spi_slv_deinit(struct mld_spi_slv_module *bus);

sint32 mld_spi_slv_vector_transmit_receive(struct mld_spi_slv_module *bus, struct mld_spi_slv_device *dev, \
                                       struct mld_spi_slv_async *vector);

sint32 mld_spi_slv_vector_transmit_receive_irq(struct mld_spi_slv_module *bus, struct mld_spi_slv_device *dev, \
        struct mld_spi_slv_async *vector);

sint32 mld_spi_slv_vector_transmit_receive_dma(struct mld_spi_slv_module *bus, struct mld_spi_slv_device *dev, \
        struct mld_spi_slv_async *vector);

sint32 mld_spi_slv_async_polling(struct mld_spi_slv_module *bus);

void spi_slv_readwrite_remain(struct mld_spi_slv_module *bus);

sint32 spi_slv_write_remain(struct mld_spi_slv_module *bus);

sint32 spi_slv_read_remain(struct mld_spi_slv_module *bus);

void mld_spi_slv_stop(struct mld_spi_slv_module *bus);

void mld_spi_slv_dev_init(struct mld_spi_slv_device *dev,void *priv);

void mld_spi_slv_dev_attach_bus(struct mld_spi_slv_device *dev, struct mld_spi_slv_module *bus);
/**
 * @description:
 * @param {mld_spi_slv_module} *bus
 * @param {void} *bus_priv
 * @param {void*} dev_mode
 * @return {*}
 */
void mld_spi_slv_bus_set_privdata(struct mld_spi_slv_module *bus,void *bus_priv, void *dev_mode);
/**
 * @description:
 * @param {mld_spi_slv_module} *bus
 * @param {uint32} base
 * @param {mld_spi_slv_ops*} ops
 * @return {*}
 */
void mld_spi_slv_bus_create(struct mld_spi_slv_module *bus,uint32 base, const struct mld_spi_slv_ops *ops);

void sync_finished_callback(struct mld_spi_slv_module *bus);

void next_async_item_cb(struct mld_spi_slv_async *src,struct mld_spi_slv_async *dst);

sint32 mld_spi_slv_get_length(struct mld_spi_slv_module *bus);

#ifdef __cplusplus
}
#endif

#endif

